/*
 * Copyright (c) 2023 Cshoo Org. All Rights Reserved.
 */

package org.cshoo.tattoo.datacenter.domain.service;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.cshoo.tattoo.datacenter.domain.bo.TemplateBo;
import org.cshoo.tattoo.datacenter.domain.constant.TemplateType;
import org.cshoo.tattoo.datacenter.domain.po.Template;
import org.cshoo.tattoo.datacenter.domain.repository.ITemplateRepository;
import org.cshoo.tattoo.embed.infra.entity.FileEntity;
import org.cshoo.tattoo.embed.infra.entity.PageQueryEntity;
import org.cshoo.tattoo.embed.infra.exception.ValidateException;
import org.cshoo.tattoo.embed.infra.utils.FileEntityUtils;
import org.cshoo.tattoo.embed.infra.utils.UserUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author 杨翼
 * @since 1.0
 */
@Service
@Slf4j
public class TemplateService {

    /**
     * 用于正则匹配UUID
     */
    private static final String UUID_REGEX = "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$";

    /**
     * 表示存放模板文件的文件夹路径
     */
    @Value("${template.file.dir.path:/tmp/template}")
    private String templateFileDirPath;

    @Resource
    private ITemplateRepository templateRepository;

    /**
     * 添加一个模板
     *
     * @param template 模板对象
     */
    public void addTemplate(Template template) throws ValidateException {
        this.validateTemplate(template);
        templateRepository.save(template);
    }

    /**
     * 修改一个模板
     *
     * @param template 模板对象
     */
    public void updateTemplate(Template template) throws ValidateException {
        Template dbTemplate = templateRepository.findById(template.getId()).orElse(null);
        if (Objects.nonNull(dbTemplate)) {
            template.setType(dbTemplate.getType());
            this.validateTemplate(template);
            template.setLastModifiedBy(UserUtils.getUser().getUsername());
            template.setLastModifiedDate(new Date());
            templateRepository.updateTemplate(template);
        }
    }

    /**
     * 查询模板
     *
     * @param templatePageReq 模板分页查询请求
     * @return 模板查询结果集
     */
    public Page<TemplateBo> queryTemplates(PageQueryEntity<String> templatePageReq) {
        PageRequest pageRequest = PageRequest.of(templatePageReq.getPageNumber(), templatePageReq.getPageSize());
        String keyword = templatePageReq.getQuery();
        Page<Template> templates = templateRepository.queryTemplates(keyword, pageRequest);

        List<TemplateBo> content = templates.stream()
                .map(template -> {
                    TemplateBo templateBo = new TemplateBo();
                    BeanUtils.copyProperties(template, templateBo);
                    String fileStoreName = template.getFileStoreName();
                    File metadataFile = new File(templateFileDirPath + File.separator + fileStoreName + ".metadata.txt");
                    templateBo.setFileName(FileEntityUtils.getFileName(metadataFile));
                    return templateBo;
                })
                .collect(Collectors.toList());

        return new PageImpl<>(
                content,
                templates.getPageable(),
                templates.getTotalElements());
    }

    /**
     * 检查编号是否存在
     *
     * @param code 编号
     * @return 检查结果
     */
    public boolean checkTemplateCodeExists(String code) {
        Template template = templateRepository.findByCode(code);
        return Objects.nonNull(template);
    }

    /**
     * 删除模板
     *
     * @param id 模板id
     */
    public void deleteTemplate(Long id) {
        templateRepository.deleteById(id);
    }

    /**
     * 查询单个模板
     *
     * @param code 编号
     * @return 模板
     */
    public Template querySingleTemplate(String code) {
        return templateRepository.findByCode(code);
    }

    /**
     * 上传模板文件
     *
     * @param file 文件
     * @return 文件存储名称
     */
    public String uploadTemplateFile(MultipartFile file) throws IOException {
        String fileStoreName = UUID.randomUUID().toString();
        String metaDataStr = FileEntityUtils.buildMetadata(file);
        FileUtils.write(new File(templateFileDirPath + File.separator + fileStoreName + ".metadata.txt"), metaDataStr, StandardCharsets.UTF_8);
        FileUtils.copyInputStreamToFile(file.getInputStream(), new File(templateFileDirPath + File.separator + fileStoreName));
        return fileStoreName;
    }

    /**
     * 下载模板文件
     *
     * @param fileStoreName 文件存储名称
     * @return 输入流
     */
    public FileEntity downloadTemplateFile(String fileStoreName) throws IOException, ValidateException {
        if (!fileStoreName.matches(UUID_REGEX)) {
            throw new ValidateException("File store name + [" + fileStoreName + "] is invalid");
        }

        File file = new File(templateFileDirPath + File.separator + fileStoreName);
        File metadataFile = new File(templateFileDirPath + File.separator + fileStoreName + ".metadata.txt");
        if (!file.exists() || !metadataFile.exists()) {
            throw new FileNotFoundException("This file [" + fileStoreName + "] is not exist");
        }
        String metadata = FileUtils.readFileToString(metadataFile, StandardCharsets.UTF_8);
        return FileEntityUtils.buildFileEntity(file, metadata);
    }

    /**
     * 校验模板数据
     *
     * @param template 模板
     */
    private void validateTemplate(Template template) throws ValidateException {
        if (Objects.equals(template.getType(), TemplateType.TEXT.getValue())) {
            if (StringUtils.isBlank(template.getContent())) {
                throw new ValidateException("The content of the TEXT template is required");
            }
        } else if (Objects.equals(template.getType(), TemplateType.FILE.getValue())) {
            if (StringUtils.isBlank(template.getFileStoreName())) {
                throw new ValidateException("The fileStoreName of the FILE template is required");
            }
        }
        else {
            throw new ValidateException("The type value can only be limited to 1 for the TEXT template and 2 for the FILE template");
        }

    }
}
